home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / redakcyjne / programy / VideoLAN Client (VLC) 1.0.5 / vlc-1.0.5-win32.exe / lua / intf / modules / host.lua < prev    next >
Text File  |  2010-01-30  |  10KB  |  330 lines

  1. --[==========================================================================[
  2.  host.lua: VLC Lua interface command line host module
  3. --[==========================================================================[
  4.  Copyright (C) 2007 the VideoLAN team
  5.  $Id$
  6.  
  7.  Authors: Antoine Cellerier <dionoea at videolan dot org>
  8.  
  9.  This program is free software; you can redistribute it and/or modify
  10.  it under the terms of the GNU General Public License as published by
  11.  the Free Software Foundation; either version 2 of the License, or
  12.  (at your option) any later version.
  13.  
  14.  This program is distributed in the hope that it will be useful,
  15.  but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.  GNU General Public License for more details.
  18.  
  19.  You should have received a copy of the GNU General Public License
  20.  along with this program; if not, write to the Free Software
  21.  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  22. --]==========================================================================]
  23.  
  24. --[==========================================================================[
  25. Example use:
  26.  
  27.     require "host"
  28.     h = host.host()
  29.  
  30.     -- Bypass any authentification
  31.     function on_password( client )
  32.         client:switch_status( host.status.read )
  33.     end
  34.     h.status_callbacks[host.status.password] = on_password
  35.  
  36.     h:listen( "localhost:4212" )
  37.     h:listen( "*console" )
  38.     --or h:listen( { "localhost:4212", "*console" } )
  39.  
  40.     -- The main loop
  41.     while not vlc.misc.should_die() do
  42.         -- accept new connections
  43.         h:accept()
  44.  
  45.         -- select active clients
  46.         local write, read = h:select( 0.1 ) -- 0.1 is a timeout in seconds
  47.  
  48.         -- handle clients in write mode
  49.         for _, client in pairs(write) do
  50.             client:send()
  51.             client.buffer = ""
  52.             client:switch_status( host.status.read )
  53.         end
  54.  
  55.         -- handle clients in read mode
  56.         for _, client in pairs(read) do
  57.             local str = client:recv(1000)
  58.             str = string.gsub(str,"\r?\n$","")
  59.             client.buffer = "Got `"..str.."'.\r\n"
  60.             client:switch_status( host.status.write )
  61.         end
  62.     end
  63.  
  64. For complete examples see existing VLC Lua interface modules (ie telnet.lua)
  65. --]==========================================================================]
  66.  
  67. module("host",package.seeall)
  68.  
  69. status = { init = 0, read = 1, write = 2, password = 3 }
  70. client_type = { net = 1, stdio = 2, fifo = 3 }
  71.  
  72. function host()
  73.     -- private data
  74.     local clients = {}
  75.     local listeners = {}
  76.     local status_callbacks = {}
  77.  
  78.     -- private data
  79.     local fds_read = vlc.net.fd_set_new()
  80.     local fds_write = vlc.net.fd_set_new()
  81.  
  82.     -- private methods
  83.     local function client_accept( clients, listen )
  84.         local wait
  85.         if #clients == 0 then
  86.             wait = -1
  87.         else
  88.             wait = 0
  89.         end
  90.         return listen:accept( wait )
  91.     end
  92.  
  93.     local function fd_client( client )
  94.         if client.status == status.read then
  95.             return client.rfd
  96.         else -- status.write
  97.             return client.wfd
  98.         end
  99.     end
  100.  
  101.     local function send( client, data, len )
  102.         if len then
  103.             return vlc.net.send( client.wfd, data, len )
  104.         else
  105.             return vlc.net.send( client.wfd, data or client.buffer )
  106.         end
  107.     end
  108.  
  109.     local function recv( client, len )
  110.         if len then
  111.             return vlc.net.recv( client.rfd, len )
  112.         else
  113.             return vlc.net.recv( client.rfd )
  114.         end
  115.     end
  116.  
  117.     local function write( client, data )
  118.         return vlc.net.write( client.wfd, data or client.buffer )
  119.     end
  120.  
  121.     local function read( client, len )
  122.         if len then
  123.             return vlc.net.read( client.rfd, len )
  124.         else
  125.             return vlc.net.read( client.rfd )
  126.         end
  127.     end
  128.  
  129.     local function del_client( client )
  130.         if client.type == client_type.stdio then
  131.             client:send( "Cannot delete stdin/stdout client.\n" )
  132.             return
  133.         end
  134.         for i, c in pairs(clients) do
  135.             if c == client then
  136.                 if client.type == client_type.net then
  137.                     if client.wfd ~= client.rfd then
  138.                         vlc.net.close( client.rfd )
  139.                     end
  140.                     vlc.net.close( client.wfd )
  141.                 end
  142.                 clients[i] = nil
  143.                 return
  144.             end
  145.         end
  146.         vlc.msg.err("couldn't find client to remove.")
  147.     end
  148.     
  149.     local function switch_status( client, s )
  150.         if client.status == s then return end
  151.         client.status = s
  152.         if status_callbacks[s] then
  153.             status_callbacks[s]( client )
  154.         end
  155.     end
  156.  
  157.     -- append a line to a client's (output) buffer
  158.     local function append( client, string )
  159.         client.buffer = client.buffer .. string .. "\r\n"
  160.     end
  161.  
  162.     local function new_client( h, fd, wfd, t )
  163.         if fd < 0 then return end
  164.         local w, r
  165.         if t == client_type.net then
  166.             w = send
  167.             r = recv
  168.         else if t == client_type.stdio or t == client_type.fifo then
  169.             w = write
  170.             r = read
  171.         else
  172.             error("Unknown client type", t )
  173.         end end
  174.         local client = { -- data
  175.                          rfd = fd,
  176.                          wfd = wfd or fd,
  177.                          status = status.init,
  178.                          buffer = "",
  179.                          type = t,
  180.                          -- methods
  181.                          fd = fd_client,
  182.                          send = w,
  183.                          recv = r,
  184.                          del = del_client,
  185.                          switch_status = switch_status,
  186.                          append = append,
  187.                        }
  188.         client:send( "VLC media player "..vlc.misc.version().."\n" )
  189.         table.insert(clients, client)
  190.         client:switch_status(status.password)
  191.     end
  192.  
  193.     function filter_client( fd, status, status2 )
  194.         local l = 0
  195.         fd:zero()
  196.         for _, client in pairs(clients) do
  197.             if client.status == status or client.status == status2 then
  198.                 fd:set( client:fd() )
  199.                 l = math.max( l, client:fd() )
  200.             end
  201.         end
  202.         return l
  203.     end
  204.  
  205.     -- public methods
  206.     local function _listen_tcp( h, host, port )
  207.         if listeners.tcp and listeners.tcp[host]
  208.                          and listeners.tcp[host][port] then
  209.             error("Already listening on tcp host `"..host..":"..tostring(port).."'")
  210.         end
  211.         if not listeners.tcp then
  212.             listeners.tcp = {}
  213.         end
  214.         if not listeners.tcp[host] then
  215.             listeners.tcp[host] = {}
  216.         end
  217.         local listener = vlc.net.listen_tcp( host, port )
  218.         listeners.tcp[host][port] = listener
  219.         if not listeners.tcp.list then
  220.             -- FIXME: if host == "list" we'll have a problem
  221.             listeners.tcp.list = {}
  222.             local m = { __mode = "v" } -- week values
  223.             setmetatable( listeners.tcp.list, m )
  224.         end
  225.         table.insert( listeners.tcp.list, listener )
  226.     end
  227.  
  228.     local function _listen_stdio( h )
  229.         
  230.         if listeners.stdio then
  231.             error("Already listening on stdio")
  232.         end
  233.         new_client( h, 0, 1, client_type.stdio )
  234.         listeners.stdio = true
  235.     end
  236.  
  237.     local function _listen( h, url )
  238.         if type(url)==type({}) then
  239.             for _,u in pairs(url) do
  240.                 h:listen( u )
  241.             end
  242.         else
  243.             vlc.msg.info( "Listening on host \""..url.."\"." )
  244.             if url == "*console" then
  245.                 h:listen_stdio()
  246.             else
  247.                 u = vlc.net.url_parse( url )
  248.                 h:listen_tcp( u.host, u.port )
  249.             end
  250.         end
  251.     end
  252.  
  253.     local function _accept( h )
  254.         if listeners.tcp then
  255.             local wait
  256.             if #clients == 0 and not listeners.stdio and #listeners.tcp.list == 1 then
  257.                 wait = -1 -- blocking
  258.             else
  259.                 wait = 0
  260.             end
  261.             for _, listener in pairs(listeners.tcp.list) do
  262.                 local fd = listener:accept( wait )
  263.                 new_client( h, fd, fd, client_type.net )
  264.             end
  265.         end
  266.     end
  267.  
  268.     local function _select( h, timeout )
  269.         local nfds = math.max( filter_client( fds_read, status.read, status.password ),
  270.                                filter_client( fds_write, status.write ) ) + 1
  271.         local ret = vlc.net.select( nfds, fds_read, fds_write,
  272.                                     timeout or 0.5 )
  273.         local wclients = {}
  274.         local rclients = {}
  275.         if ret > 0 then
  276.             for _, client in pairs(clients) do
  277.                 if fds_write:isset( client:fd() ) then
  278.                     table.insert(wclients,client)
  279.                 end
  280.                 if fds_read:isset( client:fd() ) then
  281.                     table.insert(rclients,client)
  282.                 end
  283.             end
  284.         end
  285.         return wclients, rclients
  286.     end
  287.  
  288.     local function destructor( h )
  289.         print "destructor"
  290.         for _,client in pairs(clients) do
  291.             client:send("Shutting down.")
  292.             if client.type == client_type.tcp then
  293.                 if client.wfd ~= client.rfd then
  294.                     vlc.net.close(client.rfd)
  295.                 end
  296.                 vlc.net.close(client.wfd)
  297.             end
  298.         end
  299.     end
  300.  
  301.     local function _broadcast( h, msg )
  302.         for _,client in pairs(clients) do
  303.             client:send( msg )
  304.         end
  305.     end
  306.  
  307.     -- the instance
  308.     local h = { -- data
  309.                 status_callbacks = status_callbacks,
  310.                 -- methods
  311.                 listen = _listen,
  312.                 listen_tcp = _listen_tcp,
  313.                 listen_stdio = _listen_stdio,
  314.                 accept = _accept,
  315.                 select = _select,
  316.                 broadcast = _broadcast,
  317.               }
  318.  
  319.     -- the metatable
  320.     local m = { -- data
  321.                 __metatable = "Nothing to see here. Move along.",
  322.                 -- methods
  323.                 __gc = destructor,
  324.               }
  325.  
  326.     setmetatable( h, m )
  327.  
  328.     return h
  329. end
  330.